using System;
using System.Diagnostics;

namespace Nice157Advices.Advices
{
    /// <summary>
    /// 15、使用dynamic来简化反射实现
    /// </summary>
    public static class _15
    {
        public static void Go ()
        {
            int times = 10000000;
            // 第一种调用方式
            DynamicSample reflectSample = new DynamicSample ();
            var addMethod = typeof (DynamicSample).GetMethod ("Add");
            Stopwatch watch1 = Stopwatch.StartNew (); ///用于测试运行时间
            for (var i = 0; i < times; i++)
            {
                addMethod.Invoke (reflectSample, new object[] { 1, 2 });
            }
            Console.WriteLine (string.Format ("普通方法反射耗时：{0} 毫秒", watch1.ElapsedMilliseconds));

            // 第二种调用方式
            dynamic dynamicSample = new DynamicSample ();
            Stopwatch watch2 = Stopwatch.StartNew ();
            for (int i = 0; i < times; i++)
            {
                dynamicSample.Add (1, 2);
            }
            Console.WriteLine (string.Format ("dynamic方式耗时：{0} 毫秒", watch2.ElapsedMilliseconds));

            // 第三种调用方式
            DynamicSample reflectSampleBetter = new DynamicSample ();
            var addMethod2 = typeof (DynamicSample).GetMethod ("Add");
            var delg = (Func<DynamicSample, int, int, int>) Delegate.CreateDelegate (typeof (Func<DynamicSample, int, int, int>), addMethod2);
            Stopwatch watch3 = Stopwatch.StartNew ();
            for (var i = 0; i < times; i++)
            {
                delg (reflectSampleBetter, 1, 2);
            }
            Console.WriteLine (string.Format ("使用dynamic优化的反射耗时：{0} 毫秒", watch3.ElapsedMilliseconds));

            // 不用反射
            var sample = new DynamicSample();
            Stopwatch watch4 = Stopwatch.StartNew();
            for (int i = 0; i < times; i++)
            {
                sample.Add(1, 2);
            }
            Console.WriteLine (string.Format ("不用反射耗时：{0} 毫秒", watch4.ElapsedMilliseconds));

        }

        private class DynamicSample
        {
            public string Name { get; set; }
            public int Add (int a, int b) => a + b;
        }
    }
}